﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Asianet.Properties;
using Asianet.Resources;
using System.Net;
using System.Threading;
using System.Timers;
using System.IO;
using com.gui.effects.minToTray;
using System.Reflection;
using System.Windows.Media.Animation;

namespace Asianet
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        System.Timers.Timer Keep_Alive = new System.Timers.Timer();

        #region Global Variables <> Settings mapping
        public string UA                = Asianet.Properties.Settings.Default.UserAgent;
        public Uri GlobalURI            = Asianet.Properties.Settings.Default.GlobalURL;
        public string HostName          = Asianet.Properties.Settings.Default.Hostname;
        public string Username          = Asianet.Properties.Settings.Default.User;
        public string Passwd            = Asianet.Properties.Settings.Default.Pass;
        public string EncodingType      = Asianet.Properties.Settings.Default.EncType;
        public bool autoLoginEnabled    = Asianet.Properties.Settings.Default.autoLogin;
        public bool DebugEnabled        = Asianet.Properties.Settings.Default.Debug;
        #endregion

        public MainWindow()
        {
            
            InitializeComponent();
            /** Enable minimize to tray **/
            MinToTray.Enable(this, Ico_Resource.Asianet_logo);

            Keep_Alive.AutoReset = true;
            Keep_Alive.Enabled = true;
            Keep_Alive.Interval = 300000; // 300000 timeout specified in the code
            Keep_Alive.Elapsed +=new ElapsedEventHandler(Keep_Alive_Elapsed);
        }

        private void Keep_Alive_Elapsed(object sender, ElapsedEventArgs e)
        {
            //Send keep alive within specified time limit
            Send_KeepAlive();
        }

        public void Login()
        {
          //  Dispatcher.Invoke(new Action(() => { Status_ellipse.Fill = Brushes.Yellow; }));
            string HtmlResult = "Not Able To Connect To Server";
            //%24PORTAL_REDIRURL%24
            string myParameters = String.Format("auth_user={0}&auth_pass={1}&accept=Login+%3E%3E",
                                                 Username, Passwd);
            try
            {
                using (WebClient wc = new WebClient())
                {
                    wc.Headers[HttpRequestHeader.Host] = HostName;
                    wc.Headers[HttpRequestHeader.ContentType] = EncodingType;
                    wc.Headers[HttpRequestHeader.UserAgent] = UA;
                    

                    /** Send the payload **/
                    HtmlResult = wc.UploadString(GlobalURI, myParameters);

                    if (!HtmlResult.Contains("failed"))
                    {
                        /** Update the GUI on Successful login **/
                        Dispatcher.Invoke(new Action(() =>
                        {
                            /*   Status_ellipse.Fill = Brushes.GreenYellow;*/
                            ShowStatusMessage(Username + " is successfully logged in !!!");
                            ConnectionStatusIndicator(Brushes.YellowGreen, fillMode.Full);
                            // Update the button logic once login is successfull else dont do it
                            changeLogin_outButtonContent("Login");
                        }));

                        // Minimize to tray once logged in. 
                        Dispatcher.Invoke(new Action(() =>
                        {
                            this.WindowState = System.Windows.WindowState.Minimized;
                        }));

                        // if login is successfull  then start sending the keep alive packet
                        Keep_Alive.Start();
                    }
                    else
                    {
                        ShowStatusMessage("Unable To Log In !! Please Check Your Username and Password");
                        ConnectionStatusIndicator(Brushes.Blue, fillMode.Partial);
                    }
                }

            }
            catch (WebException ex)
            {
                //MessageBox.Show(ex.Message, "Web exception while trying to connect", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation);

                Dispatcher.Invoke(new Action(() =>
                {
                    /*Status_ellipse.Fill = Brushes.Black;*/
                    // fall back dont need the below lines here but just in case / we dont neeed in the web exception but general exception might need it
                    // changeLogin_outButtonContent("Login");
                    ShowStatusMessage("Cannot log in using " + Username + " - " + ex.Message);
                    ConnectionStatusIndicator(Brushes.Blue, fillMode.Partial);
                }));

            }
            catch (ArgumentNullException ex)
            {
                //MessageBox.Show(ex.Message, "Parameter missing or parameter type mismatch", MessageBoxButton.OKCancel, MessageBoxImage.Error);
                Dispatcher.Invoke(new Action(() =>
                {
                    /*  Status_ellipse.Fill = Brushes.Black;*/
                    // fall back dont need the below lines here but just in case
                    // changeLogin_outButtonContent("Login");
                    ShowStatusMessage("Cannot log in using " + Username + " - " + ex.Message);
                    ConnectionStatusIndicator(Brushes.Blue, fillMode.Partial);
                }));
            }
            catch (Exception ex)
            { 
            // General exception raised from any other child nodes
                throw ex;
            }
            finally
            {
                if (DebugEnabled)
                {
                    MessageBox.Show(HtmlResult);
                }
            }
          }

        public void Logout()
          {

              string myParameters = String.Format("logout_id={0}&logout=Logout", Username);
              try
              {
                  using (WebClient wc = new WebClient())
                  {
                      wc.Headers[HttpRequestHeader.Host]        = HostName;
                      wc.Headers[HttpRequestHeader.ContentType] = EncodingType;
                      wc.Headers[HttpRequestHeader.UserAgent]   = UA;
                      /** Send the Payload **/
                      string HtmlResult = wc.UploadString( GlobalURI, myParameters);
                      /** If logout successful update the status **/
                      Dispatcher.Invoke(new Action(() =>
                      {
                          /*Status_ellipse.Fill = Brushes.Red;*/
                          ShowStatusMessage(Username + " is successfully logged out !!!");
                          ConnectionStatusIndicator(Brushes.Red, fillMode.Step);
                          changeLogin_outButtonContent("Logout");
                      }));
                      if (DebugEnabled)
                      {
                          MessageBox.Show(HtmlResult);
                      }
                  }
                  Keep_Alive.Stop();
              }
              catch (WebException ex)
              {
                 // MessageBox.Show(ex.Message, "Web exception while trying to disconnect", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation);
                  Dispatcher.Invoke(new Action(() =>
                  {
                      //  Status_ellipse.Fill = Brushes.Black;
                      // fall back dont need the below lines here but just in case / not needed here
                      // changeLogin_outButtonContent("Login");
                      ShowStatusMessage("Cannot log out using " + Username + " - " + ex.Message);
                      ConnectionStatusIndicator(Brushes.Blue, fillMode.Partial);
                  }));

              }
              catch (ArgumentNullException ex)
              {
                  MessageBox.Show(ex.Message, "Parameter missing or parameter type mismatch", MessageBoxButton.OKCancel, MessageBoxImage.Error);
                  Dispatcher.Invoke(new Action(() =>
                  {
                      /* Status_ellipse.Fill = Brushes.Black;*/
                      // fall back dont need the below lines here but just in case / not needed here
                      // changeLogin_outButtonContent("Login");
                      ShowStatusMessage("Cannot log out using " + Username + " - " + ex.Message);
                      ConnectionStatusIndicator(Brushes.Blue, fillMode.Partial);
                  }));
              }
              catch (Exception ex)
              {
                  // General Exception rethrow it
                  throw ex;
              }
              finally
              { 
              }
        }

        public void Send_KeepAlive()
        {
            string myParameters = String.Format("alive=y&un={0}", Username);
            try
            {
                using (WebClient wc = new WebClient())
                {
                    wc.Headers[HttpRequestHeader.Host]          = HostName;
                    wc.Headers[HttpRequestHeader.ContentType]   = EncodingType;
                    wc.Headers[HttpRequestHeader.UserAgent]     = UA;
                    /** Send the payload **/
                    string HtmlResult = wc.UploadString( GlobalURI, myParameters);

                }
            }
            catch (WebException ex)
            {
                //MessageBox.Show(ex.Message, "Web exception while to send Keep Alive", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation);
                Dispatcher.Invoke(new Action(() =>
                {
                    // Status_ellipse.Fill = Brushes.Black;
                    // fall back by stoping the keep alive beats
                    ShowStatusMessage("Cannot send keep alive message  - " + ex.Message);
                    ConnectionStatusIndicator(Brushes.Blue, fillMode.Partial);
                    Keep_Alive.Stop();
                }));

            }
            catch (ArgumentNullException ex)
            {
                //MessageBox.Show(ex.Message, "Parameter missing or parameter type mismatch", MessageBoxButton.OKCancel, MessageBoxImage.Error);
                Dispatcher.Invoke(new Action(() =>
                {
                    //  Status_ellipse.Fill = Brushes.Black;
                    // fall back by stoping the keep alive beats
                    ShowStatusMessage("Cannot send keep alive message  - " + ex.Message);
                    ConnectionStatusIndicator(Brushes.Blue, fillMode.Partial);
                    Keep_Alive.Stop();
                }));
            }
            catch (Exception ex)
            { 
            // General exception so rethrow it and handle in the root
                throw ex;
            }
            finally
            {


            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ConnectionStatusIndicator(Brushes.Yellow, fillMode.Step);
            if (autoLoginEnabled) LoginProxy(true);
        }

        private void enableSettingsControls()
        {
            // Alternatively we can add the controls to a grid and hide the grid but I am lazy :)
            tbURL.Visibility        = System.Windows.Visibility.Visible;
            tbUserName.Visibility   = System.Windows.Visibility.Visible;
            passwordBox.Visibility  = System.Windows.Visibility.Visible;
            label1.Visibility       = System.Windows.Visibility.Visible;
            label2.Visibility       = System.Windows.Visibility.Visible;
            label3.Visibility       = System.Windows.Visibility.Visible;
            cbAutoLogin.Visibility  = System.Windows.Visibility.Visible;
            cbDebug.Visibility      = System.Windows.Visibility.Visible;

            btnSave.Visibility      = System.Windows.Visibility.Visible;
            btnCancel.Visibility    = System.Windows.Visibility.Visible;

            // Loads the settings page data
            FeedSettingsPage();
        }

        private void disableSettingsControls()
        {
            // [CTRL C + CTRL V] Alternatively we can add the controls to a grid and hide the grid but I am lazy :)
            tbURL.Visibility        = System.Windows.Visibility.Hidden;
            tbUserName.Visibility   = System.Windows.Visibility.Hidden;
            passwordBox.Visibility  = System.Windows.Visibility.Hidden;
            label1.Visibility       = System.Windows.Visibility.Hidden;
            label2.Visibility       = System.Windows.Visibility.Hidden;
            label3.Visibility       = System.Windows.Visibility.Hidden;
            cbAutoLogin.Visibility  = System.Windows.Visibility.Hidden;
            cbDebug.Visibility      = System.Windows.Visibility.Hidden;

            btnSave.Visibility      = System.Windows.Visibility.Hidden;
            btnCancel.Visibility    = System.Windows.Visibility.Hidden;
        }

        private void enableHomeControls()
        {
            //btnLogin_Out.Visibility = System.Windows.Visibility.Visible;
        }

        private void disableHomeControls()
        {
            //btnLogin_Out.Visibility = System.Windows.Visibility.Hidden;
        }

        private void window_MouseDown(object sender, MouseButtonEventArgs e)
        {
            DragMove();
        }

        private void changeLogin_outButtonContent(string currentState)
        {
            if (currentState == "Login")
            {
                //Changing the buton status
                btn_Login_Out.Content = "Logout";
                //Really sloppy code , need to find an alternative
                btn_Login_Out.Style = (System.Windows.Style)FindResource("LogoutButtonStyle");
            }
            else 
            {
                //Changing the buton status
                btn_Login_Out.Content = "Login";
                // Really sloppy code 
                btn_Login_Out.Style = (System.Windows.Style)FindResource("LoginButtonStyle");
            }
        
        }

        private void btn_LogIn_Out_Click(object sender, RoutedEventArgs e)
        {
            Panel.SetZIndex(Top, 1);
            Panel.SetZIndex(Bottom, -1);

            //Enabling Home Controls
            enableHomeControls();

            // Disabling settings controls
            disableSettingsControls();

            if (btn_Login_Out.Content.ToString() == "Login")
            {
                try
                {
                    LoginProxy(true);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error in Log In : " + ex);
                }
                // --> If threading isnt used we can change button content using the following lines else let it be !!
                // changeLogin_outButtonContent("Login");
            }
            else
            {
                try
                {
                    ShowStatusMessage("Trying to log out !!");
                    // Initiating Log out 
                    Logout();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error in Logout() : " + ex);
                }
                // --> If threading isnt used we can change button content using the following lines else let it be !!
                //  changeLogin_outButtonContent("Logout");
            }
        }

        private void btn_Close_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            string ErrorMsg = "" ;
            if (tbUserName.Text != "")
            {
                Asianet.Properties.Settings.Default.User = tbUserName.Text;
            }
            else
            {
                ErrorMsg += "Username Cannot Be Empty" + Environment.NewLine;
            }
            if (passwordBox.Password != "")
            {
                Asianet.Properties.Settings.Default.Pass = passwordBox.Password;
            }
            else
            {
                ErrorMsg += "Password Cannot Be Empty" + Environment.NewLine;
            }
            try
            {
                Asianet.Properties.Settings.Default.GlobalURL = new Uri(tbURL.Text);
                // Extract and set the hostname need to validate the port number , it might change so we need to get around this
                Asianet.Properties.Settings.Default.Hostname = Asianet.Properties.Settings.Default.GlobalURL.Host + ":8001";
            }
            catch (UriFormatException ex)
            {
                ErrorMsg += "Malformed URL Try Again !! " + ex + Environment.NewLine;
            }
            catch (ArgumentNullException ex)
            {
                ErrorMsg += "URL Cannot Be Empty" + ex + Environment.NewLine;
            }

            if (ErrorMsg != "")
            {
                ShowErrorSlider(ErrorMsg);
            }
            else
            {
                /* Check boxes and additional controls here */
                Asianet.Properties.Settings.Default.Debug     = cbDebug.IsChecked.Value;
                Asianet.Properties.Settings.Default.autoLogin = cbAutoLogin.IsChecked.Value;

                Asianet.Properties.Settings.Default.Save();

                /* Reload the values after saving */
                GlobalURI = Asianet.Properties.Settings.Default.GlobalURL;
                HostName = Asianet.Properties.Settings.Default.Hostname;
                Username = Asianet.Properties.Settings.Default.User;
                Passwd = Asianet.Properties.Settings.Default.Pass;
                autoLoginEnabled    = Asianet.Properties.Settings.Default.autoLogin;
                DebugEnabled = Asianet.Properties.Settings.Default.Debug;
            }
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            // restore default settings
            tbUserName.Text         = Asianet.Properties.Settings.Default.User;
            passwordBox.Password    = Asianet.Properties.Settings.Default.Pass;
            tbURL.Text              = Asianet.Properties.Settings.Default.GlobalURL.ToString();
            /*Check box controls here*/
        }

        private void btn_Settings_Click(object sender, RoutedEventArgs e)
        {
            Panel.SetZIndex(Top, -1);
            Panel.SetZIndex(Bottom, 1);

            //Enabling settings controls
            enableSettingsControls();

            //Disabling Home Controls
            disableHomeControls();
        }

        private void btnMini_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = System.Windows.WindowState.Minimized;
        }

        private void LoginProxy(bool isThreadingEnabled)
        {
            if (isThreadingEnabled)
            {
                try
                {
                    ShowStatusMessage("Trying to log in !!");
                    ConnectionStatusIndicator(Brushes.Yellow, fillMode.Step);
                    Thread th = new Thread(Login);
                    th.IsBackground = true;
                    th.Start();
                    //changeLogin_outButtonContent("Login");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(" An General exception was encountered : " + ex.Message);
                }
            }
            else
            {
                try
                {
                    ShowStatusMessage("Trying to log in !!");
                    ConnectionStatusIndicator(Brushes.Yellow, fillMode.Step);
                    Login();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("A General Exception was encountered : " + ex.Message );
                }
            }
        }

        private void FeedSettingsPage()
        {
            tbUserName.Text = Username;
            passwordBox.Password = Passwd;
            tbURL.Text = GlobalURI.ToString();
            cbAutoLogin.IsChecked = autoLoginEnabled;
            cbDebug.IsChecked = DebugEnabled;
        }

        private void ShowErrorSlider(string ErrorMessage)
        {
            tbErrorMsg.Text = "";
            DoubleAnimation DA_Slider = new DoubleAnimation();
            DA_Slider.From = 0;
            DA_Slider.To = 100;
            DA_Slider.Duration = TimeSpan.FromSeconds(.5);
            BottomErrorPanel.BeginAnimation( Grid.HeightProperty , DA_Slider );
            tbErrorMsg.Text = ErrorMessage;
        }

        private void btnSliderClose_Click(object sender, RoutedEventArgs e)
        {
            DoubleAnimation DA_Slider = new DoubleAnimation();
            DA_Slider.From = 100;
            DA_Slider.To = 0;
            DA_Slider.Duration = TimeSpan.FromSeconds(.5);
            BottomErrorPanel.BeginAnimation(Grid.HeightProperty, DA_Slider);
        }

        private void ShowStatusMessage(string msg)
        {
            Dispatcher.BeginInvoke(new Action(() => 
            {
                tBlkStatusMsg.Text = msg;
            }));
        }

        private void ConnectionStatusIndicator(Brush fillColor , fillMode mode)
        {
            //Clear the connection status indicator.
            Dispatcher.BeginInvoke(new Action(() =>
            {
                rcon0.Fill = Brushes.Transparent;
                rcon1.Fill = Brushes.Transparent;
                rcon2.Fill = Brushes.Transparent;
                rcon3.Fill = Brushes.Transparent;
            }));
            switch (mode)
            {
                case fillMode.Full:
                    {
                        Dispatcher.BeginInvoke(new Action(() =>
                        {
                            rcon0.Fill = fillColor;
                            rcon1.Fill = fillColor;
                            rcon2.Fill = fillColor;
                            rcon3.Fill = fillColor;
                        }));
                    }
                    break;

                case fillMode.Partial:
                    {
                        Dispatcher.BeginInvoke(new Action(() =>
                        {
                            rcon0.Fill = fillColor;
                            rcon1.Fill = fillColor;
                        }));
                    }
                    break;
                case fillMode.Step:
                    {
                        // Messed Up code :(
                        Dispatcher.BeginInvoke(new Action(() =>
                        {
                            rcon0.Fill = fillColor;
                            // No need of thread sleeper here
                            Thread.Sleep(100);
                            rcon1.Fill = fillColor;
                            Thread.Sleep(100);
                            rcon2.Fill = fillColor;
                            Thread.Sleep(100);
                            rcon3.Fill = fillColor;
                        }));
                    }
                    break;
            }

        }

        enum fillMode 
        {
            Full,
            Partial,
            Step
        };
     }
}
